package io.net;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.concurrent.Executors;

public class NIODemo {

    /**
     * NIO的三大组件：Selector、Channel、Buffer
     * <p>
     * 基本数据类型除了Boolean型都有对应的Buffer
     * Buffer的本质是一个数组
     * Buffer可以同时实现读或者写，需要一个flip方法进行转换
     * <p>
     * Channel也是双向的
     * <p>
     * Selector对应一个线程，可以对接多个Channel
     */

    public static void main(String[] args) throws Exception {

        Executors.newSingleThreadExecutor().execute(NIODemo::server);

        Thread.sleep(3000);

        Executors.newSingleThreadExecutor().execute(NIODemo::client);
    }

    public static void client() {

        try {
            SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8899));
            // 切换为非阻塞模式
            socketChannel.configureBlocking(false);

            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()) {
                socketChannel.write(ByteBuffer.wrap(scanner.next().getBytes()));
            }

            scanner.close();
            socketChannel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void server() {

        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 切换为非阻塞模式
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.bind(new InetSocketAddress(8899));

            // 获取选择器
            Selector selector = Selector.open();
            // 将通道户注册到选择器上，并指定监听某个事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            // 轮询式的获取选择器上已经准备就绪的事件
            while (selector.select() > 0) {
                // 获取当前选择器中所有注册的 已就绪监听事件
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    // 获取准备准备就绪的事件
                    SelectionKey selectionKey = iterator.next();
                    iterator.remove();
                    // 如果是接收事件就绪
                    if (selectionKey.isAcceptable()) {
                        // 获取客户端连接
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        // 切换为非阻塞模式
                        socketChannel.configureBlocking(false);
                        // 将通道注册到选择器上（可以直接把ByteBuffer传进去，后面使用，也可以不传，后面再创建）
                        socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                    } else if (selectionKey.isReadable()) {
                        // 获取当前接收器上的读就绪状态
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
                        int len = 0;
                        while ((len = socketChannel.read(buffer)) > 0) {
                            System.out.println(":::" + new String(buffer.array(), 0, len));
                            buffer.clear();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}